#include "hcpp/ptp2_datasets.h"

#include "hal/sysconf_hal.h"

#include "hcpp_config.h"

#include <string.h>

const static ptp2_clock_identity_t default_clock_identity = { .raw         = { PTP2_DEFAULT_DS_CLOCK_IDENTITY } };
const static ptp2_time_interval    default_time_inverval  = { .nanoseconds = PTP2_PORT_DS_PEER_MEAN_PATH_DELAY };

/*** DEFAULT DATASET *********************************************************/

/**
 *
 */
void
ptp2_default_ds_init(ptp2_default_ds_t *this)
{
    ptp2_default_ds_set_two_step_clock                      (this, PTP2_DEFAULT_DS_TWO_STEP_CLOCK);
    ptp2_default_ds_set_clock_identity                      (this, default_clock_identity);
    ptp2_default_ds_set_port_count                          (this, PTP2_DEFAULT_DS_PORT_COUNT);
    ptp2_default_ds_set_clock_quality                       (this, PTP2_DEFAULT_DS_CLOCK_CLASS, PTP2_DEFAULT_DS_CLOCK_ACCURACY);
    ptp2_default_ds_set_priority12                          (this, PTP2_DEFAULT_DS_PRIORITY1, PTP2_DEFAULT_DS_PRIORITY2);
    ptp2_default_ds_set_domain_number                       (this, PTP2_DEFAULT_DS_DOMAIN_NUMBER);
    ptp2_default_ds_set_slave_only                          (this, PTP2_DEFAULT_DS_SLAVE_ONLY);
    ptp2_default_ds_set_unicast_mode                        (this, PTP2_DEFAULT_DS_UNICAST_MODE);
}

/**
 *
 */
void
ptp2_default_ds_set_two_step_clock(ptp2_default_ds_t *this, bool two_step_clock)
{
    this->two_step_clock                                    = two_step_clock;
    //sysconf_hal_set_ptp_flags_two_step                      (two_step_clock);
}

/**
 *
 */
void
ptp2_default_ds_set_clock_identity(ptp2_default_ds_t *this, ptp2_clock_identity_t clock_identity)
{
    this->clock_identity                                    = clock_identity;
}

/**
 *
 */
void
ptp2_default_ds_set_port_count(ptp2_default_ds_t *this, uint8_t port_count)
{
    this->port_count                                        = port_count;
}

/**
 *
 */
void
ptp2_default_ds_set_clock_quality(ptp2_default_ds_t *this, uint8_t class, uint8_t accuracy)
{
    this->clock_quality.class                               = class;
    this->clock_quality.accuracy                            = accuracy;
    this->clock_quality.offset_scaled_log_variance          = 0;

    //sysconf_hal_set_announce_gm_clock_class                 (class);
    //sysconf_hal_set_announce_gm_clock_accurracy             (accuracy);
}

/**
 *
 */
void
ptp2_default_ds_set_priority12(ptp2_default_ds_t *this, uint8_t priority1, uint8_t priority2)
{
    this->priority1                                         = priority1;
    this->priority2                                         = priority2;
    //sysconf_hal_set_announce_prio_12                        (priority1, priority2);
}

/**
 *
 */
void
ptp2_default_ds_set_priority1(ptp2_default_ds_t *this, uint8_t priority1)
{
    this->priority1                                         = priority1;
    //sysconf_hal_set_announce_prio_1                         (priority1);
}

/**
 *
 */
void
ptp2_default_ds_set_priority2(ptp2_default_ds_t *this, uint8_t priority2)
{
    this->priority2                                         = priority2;
    //sysconf_hal_set_announce_prio_2                         (priority2);

}

/**
 *
 */
void
ptp2_default_ds_set_domain_number(ptp2_default_ds_t *this, uint8_t domain_number)
{
    this->domain_number                                     = domain_number;
    //sysconf_hal_set_ptp_domain_number                       (domain_number);
}

/**
 *
 */
void ptp2_default_ds_set_slave_only(ptp2_default_ds_t *this, bool slave_only)
{
    this->unicast_mode                                      = slave_only;
}

/**
 *
 */
void
ptp2_default_ds_set_unicast_mode(ptp2_default_ds_t *this, bool unicast_mode)
{
    this->unicast_mode                                      = unicast_mode;
    //sysconf_hal_set_ptp_flags_unicast                       (unicast_mode);
}

/*** CURRENT DATASET *********************************************************/

/**
 *
 */
void
ptp2_current_ds_init(ptp2_current_ds_t *this)
{

}

/*** PARENT DATASET **********************************************************/

/**
 * Initialize a parent dataset with its default values
 *
 * @param   this                reference to a parent dataset
 */
void
ptp2_parent_ds_init(ptp2_parent_ds_t *this)
{

}

/*** TIME PROPERTIES DATASET *************************************************/

/**
 *
 */
void
ptp2_time_properties_ds_init(ptp2_time_properties_ds_t *this)
{
    ptp2_time_properties_ds_set_current_utc_offset          (this, PTP2_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET);
    ptp2_time_properties_ds_set_current_utc_offset_valid    (this, PTP2_TIME_PROPERTIES_DS_CURRENT_UTC_OFFSET_VALID);
    ptp2_time_properties_ds_set_leap59                      (this, PTP2_TIME_PROPERTIES_DS_LEAP59);
    ptp2_time_properties_ds_set_leap61                      (this, PTP2_TIME_PROPERTIES_DS_LEAP61);
    ptp2_time_properties_ds_set_time_traceable              (this, PTP2_TIME_PROPERTIES_DS_TIME_TRACEABLE);
    ptp2_time_properties_ds_set_frequency_traceable         (this, PTP2_TIME_PROPERTIES_DS_FREQUENCY_TRACEABLE);
    ptp2_time_properties_ds_set_ptp_timescale               (this, PTP2_TIME_PROPERTIES_DS_PTP_TIMESCALE);
    ptp2_time_properties_ds_set_time_source                 (this, PTP2_TIME_PROPERTIES_DS_TIME_SOURCE);
}

/**
 *
 */
void
ptp2_time_properties_ds_set_current_utc_offset(ptp2_time_properties_ds_t *this, int16_t current_utc_offset)
{
    this->current_utc_offset                                = current_utc_offset;
    //sysconf_hal_set_announce_utc_offset                     (current_utc_offset);
}

/**
 *
 */
void
ptp2_time_properties_ds_set_current_utc_offset_valid(ptp2_time_properties_ds_t *this, bool current_utc_offset_valid)
{
    this->current_utc_offset_valid                          = current_utc_offset_valid;
    //sysconf_hal_set_ptp_flags_utc_resonable                 (current_utc_offset_valid);
}

/**
 *
 */
void
ptp2_time_properties_ds_set_leap59(ptp2_time_properties_ds_t *this, bool leap59)
{
    this->leap59                                            = leap59;
    //sysconf_hal_set_ptp_flags_leap_59                       (leap59);
}

/**
 *
 */
void
ptp2_time_properties_ds_set_leap61(ptp2_time_properties_ds_t *this, bool leap61)
{
    this->leap61                                            = leap61;
    //sysconf_hal_set_ptp_flags_leap_61                       (leap61);
}

/**
 *
 */
void
ptp2_time_properties_ds_set_time_traceable(ptp2_time_properties_ds_t *this, bool time_traceable)
{
    this->time_traceable                                    = time_traceable;
    //sysconf_hal_set_ptp_flags_time_tracable                 (time_traceable);
}

/**
 *
 */
void
ptp2_time_properties_ds_set_frequency_traceable(ptp2_time_properties_ds_t *this, bool frequency_traceable)
{
    this->frequency_traceable                               = frequency_traceable;
    //sysconf_hal_set_ptp_flags_freq_tracable                 (frequency_traceable);
}

/**
 *
 */
void
ptp2_time_properties_ds_set_ptp_timescale(ptp2_time_properties_ds_t *this, bool ptp_timescale)
{
    this->ptp_timescale                                     = ptp_timescale;
    //sysconf_hal_set_ptp_flags_ptp_timescale                 (ptp_timescale);
}

/**
 *
 */
void
ptp2_time_properties_ds_set_time_source(ptp2_time_properties_ds_t *this, ptp2_time_source_t time_source)
{
    this->time_source                                       = time_source;
    //sysconf_hal_set_ptp_time_source                         (time_source);

    if (time_source == PTP2_TIME_SOURCE_INTERNAL_OSCILLATOR) {
        //sysconf_hal_use_internal_clock(true);
    } else {
        //sysconf_hal_use_internal_clock(false);
    }
}

/*** PORT DATASET ************************************************************/

/**
 * Initialize a port dataset with its default values
 *
 * @param   this                reference to a port dataset
 */
void
ptp2_port_ds_init(ptp2_port_ds_t *this)
{
    ptp2_port_ds_set_port_identity                          (this, default_clock_identity, PTP2_PORT_DS_PORT_NUMBER);
    ptp2_port_ds_set_port_state                             (this, PTP2_PORT_DS_PORT_STATE);
    ptp2_port_ds_set_log_min_delay_req_interval             (this, PTP2_PORT_DS_LOG_MIN_DELAY_REQ_INTERVAL);
    ptp2_port_ds_set_peer_mean_path_delay                   (this, default_time_inverval);
    ptp2_port_ds_set_log_announce_interval                  (this, PTP2_PORT_DS_LOG_ANNOUNCE_INTERVAL);
    ptp2_port_ds_set_announce_receipt_timeout               (this, PTP2_PORT_DS_ANNOUNCE_RECEIPT_TIMEOUT);
    ptp2_port_ds_set_foreign_master_threshold               (this, PTP2_PORT_DS_FOREIGN_MASTER_THRESHOLD);
    ptp2_port_ds_set_foreign_master_time_window             (this, PTP2_PORT_DS_FOREIGN_MASTER_TIME_WINDOW);
    ptp2_port_ds_set_log_sync_interval                      (this, PTP2_PORT_DS_LOG_SYNC_INTERVAL);
    ptp2_port_ds_set_delay_mechanism                        (this, PTP2_PORT_DS_DELAY_MECHANISM);
    ptp2_port_ds_set_log_min_pdelay_req_interval            (this, PTP2_PORT_DS_LOG_MIN_PDELAY_REQ_INTERVAL);
    ptp2_port_ds_set_version_number                         (this, PTP2_PORT_DS_VERSION_NUMBER);
    ptp2_port_ds_set_alternate_master                       (this, PTP2_PORT_DS_ALTERNATE_MASTER, PTP2_PORT_DS_PROFILE_SPECIFIC1, PTP2_PORT_DS_PROFILE_SPECIFIC2);
}

/**
 *
 */
void
ptp2_port_ds_set_port_identity(ptp2_port_ds_t *this, ptp2_clock_identity_t clock_identity, uint16_t port_number)
{
    this->port_identity.clock_identity                      = clock_identity;
    this->port_identity.port_number         = port_number;
}

/**
 *
 */
void
ptp2_port_ds_set_clock_identity(ptp2_port_ds_t *this, ptp2_clock_identity_t clock_identity)
{
    this->port_identity.clock_identity                      = clock_identity;
}

/**
 *
 */
void
ptp2_port_ds_set_port_state(ptp2_port_ds_t *this, ptp2_port_state_t port_state)
{
    this->port_state                                        = port_state;
}

/**
 *
 */
void
ptp2_port_ds_set_log_min_delay_req_interval(ptp2_port_ds_t *this, int8_t log_min_delay_req_interval)
{
    this->log_min_delay_req_interval                        = log_min_delay_req_interval;
}

/**
 *
 */
void
ptp2_port_ds_set_peer_mean_path_delay(ptp2_port_ds_t *this, ptp2_time_interval peer_mean_path_delay)
{
    this->peer_mean_path_delay                              = peer_mean_path_delay;
}

/**
 *
 */
void
ptp2_port_ds_set_log_announce_interval(ptp2_port_ds_t *this, int8_t log_announce_interval)
{
    this->log_announce_interval                             = log_announce_interval;
}

/**
 *
 */
void
ptp2_port_ds_set_announce_receipt_timeout(ptp2_port_ds_t *this, uint8_t announce_receipt_timeout)
{
    this->announce_receipt_timeout                          = announce_receipt_timeout;
}

/**
 *
 */
void
ptp2_port_ds_set_foreign_master_threshold(ptp2_port_ds_t *this, uint8_t foreign_master_threshold)
{
    this->foreign_master_threshold                          = foreign_master_threshold;
}

/**
 *
 */
void
ptp2_port_ds_set_foreign_master_time_window(ptp2_port_ds_t *this, uint8_t foreign_master_time_window)
{
    this->foreign_master_time_window                        = foreign_master_time_window;
}

/**
 *
 */
void
ptp2_port_ds_set_log_sync_interval(ptp2_port_ds_t *this, int8_t log_sync_interval)
{
    this->log_sync_interval                                 = log_sync_interval;
}

/**
 *
 */
void
ptp2_port_ds_set_delay_mechanism(ptp2_port_ds_t *this, ptp2_delay_mechanism_t delay_mechanism)
{
    this->delay_mechanism                                   = delay_mechanism;
}

/**
 *
 */
void
ptp2_port_ds_set_log_min_pdelay_req_interval(ptp2_port_ds_t *this, int8_t log_min_pdelay_req_interval)
{
    this->log_min_pdelay_req_interval                       = log_min_pdelay_req_interval;
}

/**
 *
 */
void
ptp2_port_ds_set_version_number(ptp2_port_ds_t *this, uint8_t version_number)
{
    this->version_number                                    = version_number;
}

/**
 *
 */
void ptp2_port_ds_set_not_slave(ptp2_port_ds_t *this, bool not_slave)
{
    this->not_slave = not_slave;
}

/**
 *
 */
void ptp2_port_ds_set_local_priority(ptp2_port_ds_t *this, uint8_t local_priority)
{
    this->local_priority = local_priority;
}

/**
 *
 */
void
ptp2_port_ds_set_alternate_master(ptp2_port_ds_t *this, bool alternate_master, bool profile_specific1, bool profile_specific2)
{

    this->alternate_master                                  = alternate_master;
    this->profile_specific1                                 = profile_specific1;
    this->profile_specific2                                 = profile_specific2;
    //sysconf_hal_set_ptp_flags_alternate_master              (alternate_master, profile_specific1, profile_specific2);
}


/*** FOREIGN MASTER DATASET **************************************************/

/**
 * Initialize a foreign master dataset with its default values (0, PORT_IDENTITY_ALL)
 *
 * @param   this                reference to a foreign master dataset
 */
void
ptp2_foreign_master_ds_init(ptp2_foreign_master_ds_t *this)
{
    this->port_identity             = PTP2_PORT_IDENTITY_ALL;
    this->announce_msg_count        = 0;

    this->sender_identity           = PTP2_PORT_IDENTITY_ALL;
    this->receiver_identity         = PTP2_PORT_IDENTITY_ALL;

    this->gm_priority1              = 0;
    this->gm_clock_quality.raw      = 0;
    this->gm_priority2              = 0;
    this->gm_identity               = PTP2_CLOCK_IDENTITY_ALL;

    this->steps_removed             = 0;
}
